package com.justgame.project.cloud.common.exception;



import com.justgame.project.cloud.common.constant.Const;
import com.justgame.project.cloud.common.constant.Result;
import io.jsonwebtoken.ExpiredJwtException;
import lombok.extern.slf4j.Slf4j;
import org.apache.shiro.authc.AuthenticationException;
import org.apache.shiro.authz.AuthorizationException;
import org.apache.shiro.authz.UnauthenticatedException;
import org.apache.shiro.authz.UnauthorizedException;
import org.springframework.data.redis.RedisSystemException;
import org.springframework.http.converter.HttpMessageNotReadableException;
import org.springframework.validation.BindException;
import org.springframework.web.HttpRequestMethodNotSupportedException;
import org.springframework.web.bind.MethodArgumentNotValidException;
import org.springframework.web.bind.MissingServletRequestParameterException;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.RestControllerAdvice;
import org.springframework.web.servlet.NoHandlerFoundException;

import java.io.IOException;
import java.util.Objects;

/**
 * 异常捕获控制器
 */
@Slf4j
@RestControllerAdvice
@SuppressWarnings("all")
public class ExcHandler {

    @ExceptionHandler(Exc.class)
    public Result<?> Exc(Exc e) {
        return Result.fail(e.getMessage(),e.getCode());
    }

    /**
     * Assert报错拦截
     * @param e
     * @return
     */
    @ExceptionHandler(IllegalArgumentException.class)
    public Result<?> IllegalArgumentException(IllegalArgumentException e){
        log.error(e.getMessage(),e);
        return Result.fail(e.getMessage());
    }

    @ExceptionHandler(NoHandlerFoundException.class)
    public Result<?> NoHandlerFoundException(NoHandlerFoundException e) {
        log.error(e.getMessage(),e);
        return Result.fail(Const.RES_ERROR_PATH_CHINESE, Const.RES_ERROR_PATH);
    }

    @ExceptionHandler(HttpRequestMethodNotSupportedException.class)
    public Result<?> httpRequestMethodNotSupportedException(HttpRequestMethodNotSupportedException e) {
        log.error(e.getMessage(),e);
        return Result.fail("该方法不支持" + e.getMethod() + "请求方式，请使用" +
                        e.getSupportedHttpMethods() + "方法重试！",
                Const.RES_ERROR_METHOD);
    }

    /**
     * 无法解析RequestBody
     *
     * @param e
     * @return
     */
    @ExceptionHandler(HttpMessageNotReadableException.class)
    public Result<?> httpMessageNotReadableException(HttpMessageNotReadableException e) {
        log.error(e.getMessage(),e);
        return Result.fail("请重新检查数据！");
    }

    /**
     * 参数绑定失败
     */
    @ExceptionHandler({BindException.class})
    public Result<?> BindException(BindException e) {
        try {
            return Result.fail(Objects.requireNonNull(e.getFieldError()).getDefaultMessage());
        } catch (Exception ex) {
            ex.printStackTrace();
            return Result.fail("请重新检查数据！");
        }
    }

    /**
     * 参数校验失败
     */
    @ExceptionHandler({MethodArgumentNotValidException.class})
    public Result<?> MethodArgumentNotValidException(MethodArgumentNotValidException e) {
        try {
            return Result.fail(Objects.requireNonNull(e.getBindingResult()).getFieldError().getDefaultMessage());
        } catch (Exception ex) {
            ex.printStackTrace();
            return Result.fail("请重新检查数据！");
        }
    }


    @ExceptionHandler(AuthenticationException.class)
    public Result<?> AuthenticationException(AuthenticationException e) {
        log.error(e.getMessage(),e);
        return Result.fail("身份验证失败", Const.CODE_TOKEN_OUTDATED);
    }

    /**
     * 权限不足
     *
     * @param e
     * @return
     */
    @ExceptionHandler({UnauthorizedException.class, UnauthenticatedException.class, AuthorizationException.class})
    public Result<?> UnauthorizedException(Exception e) {
        log.error(e.getMessage(),e);
        return Result.fail(Const.RES_ERROR_AUTHORIZATION_CHINESE, Const.RES_ERROR_AUTHORIZATION);
    }


    /**
     * 登录过时
     *
     * @param e
     * @return
     */
    @ExceptionHandler(ExpiredJwtException.class)
    public Result<?> ExpiredJwtException(ExpiredJwtException e) {
        log.error(e.getMessage(),e);
        return Result.fail(Const.CODE_TOKEN_OUTDATED_CHINESE, Const.CODE_TOKEN_OUTDATED);
    }

    /**
     * 非重要的报错1
     */
    @ExceptionHandler(RedisSystemException.class)
    public void unImportantException1(RedisSystemException e) {
        log.error(e.getMessage(),e);
    }

    /**
     * 非重要的报错2
     */
    @ExceptionHandler(IOException.class)
    public void unImportantException2(IOException e) {
        log.error(e.getMessage(),e);
    }

    /**
     * 缺少必要的参数
     *
     * @param miss
     * @return
     */
    @ExceptionHandler(MissingServletRequestParameterException.class)
    public Result<?> missingServletRequestParameterException(MissingServletRequestParameterException miss) {
        return Result.fail(Const.RES_BAD_PARAMS_CHINESE, Const.RES_BAD_PARAMS);
    }


    /**
     * 最大级异常一定要置于所有异常之下
     *
     * @param e
     * @return
     */
    @ExceptionHandler({Exception.class, NullPointerException.class})
    public Result<?> Exception(Exception e) {
        log.error(e.getMessage(),e);
        return Result.fail("服务器异常！");
    }
}
